#include "server.h"

struct share_info *share_info;
static struct worker_ctl worker_ctl;
static struct monitor_ctl monitor_ctl;

static int _cnfg(char *argv0)
{/*{{{*/
    char dirname[LONG_FILE_NM_SIZE+1];
    char buf[LONG_FILE_NM_SIZE+1];
    int res;
    CNFG cnfg;
    struct cnfg_property property;

    extract_dirname(argv0, dirname);
    ALLOC_RETERR(share_info, struct share_info, -1);

    /*----- cnfg -----*/
    sprintf(buf, "%s/server.cnfg", dirname);
    if((res=cnfg_load(buf, &cnfg)))
    {
        printf("%s: load server.cnfg fail, errcode:%d\n",
                __func__, res);
        if(res > 0)
            printf("%s: line %d error\n", __func__, res);
        return -1;
    }

    /*--- ERRLOG ---*/
#ifdef _MY_DEBUG
    CLR_BUF(share_info->_errlog_.location);
    init_errlog(argv0, NULL);
#else
    strcpy(share_info->_errlog_.location, "./log");
    if((res=cnfg_get_property(cnfg, "ERRLOG", "LOCATION", 0, &property)))
    {
        if(res != RET_ERR_CNFG_PROPERTY_NOT_FOUND)
        {
            printf("%s: get ERRLOG.LOCATION fail, res:%d\n",
                    __func__, res);
            return(-1);
        }
    }
    else
    {
        if(!BUF_IS_CLR(property.value))
            strcpy(share_info->_errlog_.location, property.value);
    }
    if((res=init_errlog(argv0, share_info->_errlog_.location)))
    {
        printf("%s: init_errlog fail, res:%d\n", __func__, res);
        return(-1);
    }
#endif
    if((res=cnfg_get_property(cnfg, "ERRLOG", "TRACKING", 0, &property)))
    {
        if(res != RET_ERR_CNFG_PROPERTY_NOT_FOUND)
        {
            errlog("%s: get ERRLOG.TRACKING fail, res:%d\n",
                    __func__, res);
            return(-1);
        }
        share_info->_errlog_.tracking=IS_FALSE;
    }
    else
        share_info->_errlog_.tracking=IS_TRUE;

    // USER
    CLR_BUF(share_info->user);
    res=cnfg_get_property(cnfg, NULL, "USER", 0, &property);
    if(res)
    {
        if(res != RET_ERR_CNFG_PROPERTY_NOT_FOUND)
        {
            fprintf(stderr, "%s: get USER fail, res:%d\n",
                    __func__, res);
            return(-1);
        }
    }
    else
    {
        if(!BUF_IS_CLR(property.value))
        {
            if(strlen(property.value) > NAME_SIZE)
            {
                fprintf(stderr, "%s: USER invalid\n", __func__);
                return(-1);
            }
            strcpy(share_info->user, property.value);
        }
    }

    /*--- ACCESS ---*/
    // SERVER_PORT
    if((res=cnfg_get_property(cnfg, "ACCESS", "SERVER_PORT", 0, &property)))
    {
        errlog("%s: get ACCESS.SERVER_PORT fail, errcode:%d",
                __func__, res);
        return(-1);
    }
    if(BUF_IS_CLR(property.value) || (res=atoi(property.value)) < 1024)
    {
        errlog("%s: ACCESS.SERVER_PORT invalid", __func__);
        return(-1);
    }
    share_info->_access_.server_port=res;

    // MONITOR_PORT
    if((res=cnfg_get_property(cnfg, "ACCESS", "MONITOR_PORT", 0, &property)))
    {
        errlog("%s: get ACCESS.MONITOR_PORT fail, errcode:%d",
                __func__, res);
        return(-1);
    }
    if(BUF_IS_CLR(property.value) || (res=atoi(property.value)) < 1024)
    {
        errlog("%s: ACCESS.MONITOR_PORT invalid", __func__);
        return -1;
    }
    share_info->_access_.monitor_port=res;

    /*--- CUSTOMLOG ---*/
    // LOCATION
    CLR_BUF(share_info->_customlog_.location);
    if((res=cnfg_get_property(cnfg, "CUSTOMLOG", "LOCATION", 0, &property)))
    {
        if(res != RET_ERR_CNFG_PROPERTY_NOT_FOUND)
        {
            errlog("%s: get CUSTOMLOG.LOCATION fail, errcode:%d",
                    __func__, res);
            return(-1);
        }
    }
    else
    {
        if(!BUF_IS_CLR(property.value))
            strcpy(share_info->_customlog_.location, property.value);
    }

    cnfg_free(cnfg);

    return(0);
}/*}}}*/

static int _init()
{/*{{{*/
    char buf[10];
    int res;

    sig_ignore(SIGPIPE);
    ep_init();

    /*----- customlog -----*/
    if((res=create_dir(share_info->_customlog_.location)))
    {
        errlog("%s: create_dir fail, res:%d",
                __func__, res);
        return(-1);
    }

    if(getuid() == 0)
    {
        struct passwd *user=getpwnam(share_info->user);
        if(user)
        {
            if(setuid(user->pw_uid) == -1)
            {
                fprintf(stderr, "Change to user %s fail\n",
                        share_info->user);
                return(-1);
            }
            fprintf(stderr, "Change to user %s\n", share_info->user);
        }
        else
        {
            fprintf(stderr, "User %s not found, keep root\n",
                    share_info->user);
        }
    }

    /*----- monitor -----*/
    ALLOC_MULTI_RETERR(monitor_ctl.msg_in, char, BUFFER_SIZE+1, -1);
    ALLOC_MULTI_RETERR(monitor_ctl.msg_out, char, BUFFER_SIZE+1, -1);
    sprintf(buf, "%d", share_info->_access_.monitor_port);
    if((res=skt_listen(buf, 0, &monitor_ctl.skt)))
    {
        errlog("%s: open monitor port fail", __func__);
        return(-1);
    }
    errlog("%s: open monitor port(%d)",
            __func__, share_info->_access_.monitor_port);

    /*----- worker -----*/
    ALLOC_MULTI_RETERR(worker_ctl.msg_in, char, SOCK_MSG_SIZE+1, -1);
    //ALLOC_MULTI_RETERR(worker_ctl.msg_out, char, SOCK_MSG_SIZE+1, -1);
    // server port
    if((worker_ctl.sock=sockd_svr_listen(
                    share_info->_access_.server_port)) ==
            INVALID_SOCKET)
    {
        errlog("%s: open server port(%d) fail",
                __func__, share_info->_access_.server_port);
        return(-1);
    }
    errlog("%s: open server port(%d)",
            __func__, share_info->_access_.server_port);
    if(thrd_create((THRD_FUNC_T)thrd_worker, (void *)&worker_ctl,
                THRD_DETACH, &worker_ctl.thrd_id))
    {
        errlog("%s: worker thrd create fail", __func__);
        return(-1);
    }
    errlog("%s: worker thrd create succeed", __func__);

    return(0);
}/*}}}*/

int main(int argc, char *argv[])
{
#ifndef _MY_DEBUG
    daemon(1, 1);
#endif
    if(_cnfg(argv[0]))
        return(-1);
    if(_init())
        return(-2);
    if(thrd_monitor(&monitor_ctl))
        return(-3);
    return(0);
}
